<!DOCTYPE html>
<html lang="zh">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>可视化</title>
  <style>
    body {
      display: flex;
      flex-direction: column;
      min-height: 100vh;
      background-color: #1c023f;
      color: white;
      font-family: Arial, sans-serif;
      margin: 0;
      padding: 0;
      overflow-x: hidden;
      justify-content: center;
      align-items: center;
      position: relative;
    }

    .header,
    .footer,
    .search-container {
      max-width: 100%;
      box-sizing: border-box;
    }

    * {
      box-sizing: border-box;
    }

    .footer {
      position: fixed;
      bottom: 0;
      left: 0;
      right: 0;
      height: 80px;
      background-color: #1c023f;
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 10px 20px;
      margin-top: auto;
      z-index: 1000;
    }

    .header {
      display: flex;
      height: 60px;
      width: 100%;
      background-color: #1c023f;
      justify-content: space-between;
      align-items: center;
      padding: 0 20px;
    }

    .header h1,
    .header p {
      margin: 0;
    }

    .search-container {
      margin: 10px 20px;
      margin-top: 30px;
      display: flex;
      align-items: center;
    }

    .search-bar {
      background: #392f5a;
      border-radius: 10px;
      padding: 8px 10px;
      display: flex;
      align-items: center;
      width: 100%;
      max-width: 500px;
      position: relative;
    }

    .search-input {
      background: transparent;
      border: none;
      color: white;
      outline: none;
      flex: 1;
      margin-left: 10px;
      padding: 5px;
    }

    .search-button {
      background: #5b4aa3;
      border: none;
      border-radius: 5px;
      color: white;
      cursor: pointer;
      padding: 5px 15px;
      margin-left: 10px;
      transition: background-color 0.3s;
    }

    .search-button:hover {
      background: #4a3f8c;
    }

    .button {
      background: rgba(107, 85, 180, 0.7);
      opacity: 0.6;
      border: none;
      border-radius: 10px;
      color: white;
      padding: 12px;
      text-align: center;
      margin: 10px;
      cursor: pointer;
      transition: background-color 0.3s;
      width: 30px;
      /* 设置按钮的固定宽度 */
      height: 100px;
      /* 设置按钮的固定高度 */
      display: flex;
      align-items: center;
      justify-content: center;
    }

    .button:hover {
      background: #5b4aa3;
    }

    .footer svg {
      color: white;
      font-size: 24px;
    }

    .back-btn,
    .location-btn,
    .calendar-btn,
    .moon-btn,
    .data-btn,
    .index-btn {
      margin-right: 10px;
      background: none;
      border: none;
      padding: 0;
      cursor: pointer;
      transition: opacity 0.3s;
    }

    .back-btn:hover,
    .location-btn:hover,
    .calendar-btn:hover,
    .moon-btn:hover,
    .data-btn:hover,
    .index-btn:hover {
      opacity: 0.8;
    }

    .location-info {
      flex-grow: 1;
      text-align: right;
      padding: 30px;
    }

    .location-info h1,
    .location-info p {
      margin: 0;
    }

    .button-list {
      flex: 1;
      display: flex;
      flex-wrap: wrap;
      justify-content: center;
      /* 中心对齐 */
      align-items: center;
      /* 垂直居中对齐 */
      overflow-y: auto;
    }

    .content {
      padding: 20px;
      background: #2e1a5a;
      border-radius: 10px;
      margin: 20px;
      color: white;
      max-width: 800px;
      width: 100%;
      box-sizing: border-box;
    }

    .center-container {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      flex-grow: 1;
    }

    .image-container {
      display: flex;
      justify-content: center;
      align-items: center;
      position: relative;
    }

    .image-container img {
      max-width: 100%;
      height: auto;
    }

    .caption {
      text-align: left;
      margin-top: 10px;
      width: 100%;
      max-width: 800px;
    }
  </style>
  <style>
    body {
      margin: 0;
    }

    canvas {
      display: block;
    }

    #info {
      position: absolute;
      top: 20px !important;
      right: 10px;
      color: white;
      font-family: Arial, sans-serif;
      font-size: 14px;
      background: rgba(0, 0, 0, 0.5);
      padding: 10px;
      border-radius: 5px;
    }
  </style>
  <script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js"></script>
  <script type="importmap">
      {
        "imports": {
          "three": "https://unpkg.com/three@0.156.1/build/three.module.js",
          "three/addons/": "https://unpkg.com/three@0.156.1/examples/jsm/"
        }
      }
    </script>
  <script type="module">
    import * as THREE from "three";
    import { OrbitControls } from "three/addons/controls/OrbitControls.js";

    // 全局变量存储天轴和天极对象
    let celestialAxis,
      northPoleMark,
      southPoleMark,
      northPoleLabel,
      southPoleLabel;

    // 初始化函数
    function init() {
      // 场景初始化
      const scene = new THREE.Scene();
      scene.background = new THREE.Color(0x000000);
      const camera = new THREE.PerspectiveCamera(
        75,
        window.innerWidth / window.innerHeight,
        0.1,
        1000
      );
      const renderer = new THREE.WebGLRenderer();
      renderer.setSize(window.innerWidth, window.innerHeight);
      document.body.appendChild(renderer.domElement);

      // 添加轨道控制器
      const controls = new OrbitControls(camera, renderer.domElement);
      camera.position.set(4, 4, 4);
      controls.update();

      // 创建天球
      const radius = 2;
      const segments = 30;
      const geometry = new THREE.SphereGeometry(radius, segments, segments);
      const material = new THREE.MeshBasicMaterial({
        color: 0xffffff,
        wireframe: true,
        opacity: 0.1, // 添加透明度
        transparent: true, // 启用透明
      });
      const celestialSphere = new THREE.Mesh(geometry, material);
      scene.add(celestialSphere);

      // 创建半透明赤道平面
      const equatorialPlaneGeometry = new THREE.CircleGeometry(
        radius,
        segments
      );
      const equatorialPlaneMaterial = new THREE.MeshBasicMaterial({
        color: 0x4169e1,
        transparent: true,
        opacity: 0.2,
        side: THREE.DoubleSide,
      });
      const equatorialPlane = new THREE.Mesh(
        equatorialPlaneGeometry,
        equatorialPlaneMaterial
      );
      equatorialPlane.rotation.x = Math.PI / 2; // 添加90度旋转，使平面与赤道平行
      scene.add(equatorialPlane);

      // 创建加粗的赤道圆圈
      const equatorLineGeometry = new THREE.TorusGeometry(
        radius,
        0.003,
        16,
        100
      );
      const equatorLineMaterial = new THREE.MeshBasicMaterial({
        color: 0xffffff,
      });
      const equatorLine = new THREE.Mesh(
        equatorLineGeometry,
        equatorLineMaterial
      );
      equatorLine.rotation.x = Math.PI / 2;
      scene.add(equatorLine);

      // 添加坐标轴
      const axesHelper = new THREE.AxesHelper(radius * 1.2);
      scene.add(axesHelper);

      // 添加方位点在赤道平面上
      const orientationPoints = [];
      const orientationLabels = [
        "东",
        "东北",
        "北",
        "西北",
        "西",
        "西南",
        "南",
        "东南",
      ];
      for (let i = 0; i < 8; i++) {
        const angle = (i * Math.PI * 2) / 8;
        const x = radius * Math.cos(angle);
        const z = radius * Math.sin(angle);
        const y = 0; // 设置在赤道平面（y=0）上

        const pointGeometry = new THREE.SphereGeometry(0.02);
        const pointMaterial = new THREE.MeshBasicMaterial({
          color: 0x00ffff,
        });
        const point = new THREE.Mesh(pointGeometry, pointMaterial);
        point.position.set(x, y, z);
        scene.add(point);
        orientationPoints.push(point);

        // 添加文字标签
        const div = document.createElement("div");
        div.className = "label";
        div.textContent = orientationLabels[i];
        div.style.color = "white";
        const label = document.createElement("div");
        label.className = "label";
        label.style.position = "absolute";
        label.style.color = "white";
        label.style.padding = "2px";
        label.style.backgroundColor = "rgba(0,0,0,0.5)";
        label.textContent = orientationLabels[i];
        document.body.appendChild(label);

        // 更新标签位置
        function updateLabel() {
          const vector = new THREE.Vector3(x, y, z); // 移除1.2的缩放
          vector.project(camera);
          const x2d = (vector.x * 0.5 + 0.5) * window.innerWidth;
          const y2d = (-vector.y * 0.5 + 0.5) * window.innerHeight;
          label.style.left = x2d + "px";
          label.style.top = y2d + "px";
        }
        orientationPoints.push({ point, updateLabel });
      }

      // 添加用户输入控件
      const inputPanel = document.createElement("div");
      inputPanel.style.position = "absolute";
      inputPanel.style.top = "10px";
      inputPanel.style.left = "10px";
      inputPanel.style.background = "rgba(0,0,0,0.5)";
      inputPanel.style.padding = "10px";
      inputPanel.style.borderRadius = "5px";
      inputPanel.style.color = "white";

      // 创建半球选择
      const hemisphereLabel = document.createElement("label");
      hemisphereLabel.textContent = "半球: ";
      const hemisphereSelect = document.createElement("select");
      hemisphereSelect.innerHTML = `
            <option value="north">北半球</option>
            <option value="south">南半球</option>
        `;
      inputPanel.appendChild(hemisphereLabel);
      inputPanel.appendChild(hemisphereSelect);
      inputPanel.appendChild(document.createElement("br"));

      // 创建纬度输入
      const latitudeLabel = document.createElement("label");
      latitudeLabel.textContent = "纬度: ";
      const latitudeInput = document.createElement("input");
      latitudeInput.type = "number";
      latitudeInput.value = "35";
      latitudeInput.min = "0";
      latitudeInput.max = "90";
      latitudeInput.step = "0.1";
      inputPanel.appendChild(latitudeLabel);
      inputPanel.appendChild(latitudeInput);
      inputPanel.appendChild(document.createElement("br"));

      // 创建年份输入
      const yearLabel = document.createElement("label");
      yearLabel.textContent = "年份: ";
      const yearInput = document.createElement("input");
      yearInput.type = "number";
      yearInput.value = "2024";
      yearInput.min = "1900";
      yearInput.max = "2100";
      inputPanel.appendChild(yearLabel);
      inputPanel.appendChild(yearInput);
      inputPanel.appendChild(document.createElement("br"));

      // 创建月份输入
      const monthLabel = document.createElement("label");
      monthLabel.textContent = "月份: ";
      const monthInput = document.createElement("input");
      monthInput.type = "number";
      monthInput.value = "6";
      monthInput.min = "1";
      monthInput.max = "12";
      inputPanel.appendChild(monthLabel);
      inputPanel.appendChild(monthInput);
      inputPanel.appendChild(document.createElement("br"));

      // 创建日期输入
      const dateLabel = document.createElement("label");
      dateLabel.textContent = "日期: ";
      const dateInput = document.createElement("input");
      dateInput.type = "number";
      dateInput.value = "21";
      dateInput.min = "1";
      dateInput.max = "31";
      inputPanel.appendChild(dateLabel);
      inputPanel.appendChild(dateInput);
      inputPanel.appendChild(document.createElement("br"));

      // 创建更新按钮
      const updateButton = document.createElement("button");
      updateButton.textContent = "更新";
      updateButton.style.marginTop = "10px";
      inputPanel.appendChild(updateButton);

      document.body.appendChild(inputPanel);
      // 新增代码
      setTimeout(() => {
        const infoPanel = document.getElementById("info");
        // 计算输入面板底部位置（top + 高度 + 10px间距）
        const inputPanelBottom =
          inputPanel.offsetTop + inputPanel.offsetHeight + 10;
        // 设置信息面板新位置
        infoPanel.style.top = `${inputPanelBottom}px`;
      }, 0);
      // 获取输入值并更新场景
      let latitude = 35;
      let month = 6;
      let date = 21;
      let year = 2024;
      let isNorthernHemisphere = true;

      // 存储需要清除的对象
      let objectsToRemove = [];

      updateButton.onclick = function () {
        // 清除之前的对象
        objectsToRemove.forEach((obj) => {
          if (obj.geometry) obj.geometry.dispose();
          if (obj.material) obj.material.dispose();
          scene.remove(obj);
        });
        objectsToRemove = [];

        // 清除之前的标签（修复作用域问题）
        const timeLabels = document.querySelectorAll(".label");
        timeLabels.forEach((label) => {
          if (label.textContent.includes(":00")) {
            label.remove();
          }
        });

        // 修复parseFloat语法错误
        latitude = Math.abs(parseFloat(latitudeInput.value));
        month = parseInt(monthInput.value);
        date = parseInt(dateInput.value);
        year = parseInt(yearInput.value);
        isNorthernHemisphere = hemisphereSelect.value === "north";
        latitude = isNorthernHemisphere ? latitude : -latitude;

        // 计算赤纬角
        const delta =
          (23.45 *
            Math.sin((2 * Math.PI * (284 + (month - 1) * 30 + date)) / 365) *
            Math.PI) /
          180;

        // 计算太阳轨迹平面的法向量（与天轴重合）
        const normalVector = new THREE.Vector3(
          0, // x = 0 表示在正北方
          Math.sin((latitude * Math.PI) / 180), // y分量决定仰角
          Math.cos((latitude * Math.PI) / 180) // z分量确保距离
        ).normalize();

        // 计算北天极点位置
        // 北天极的位置：在北方，仰角等于纬度
        const latitudeRad = (latitude * Math.PI) / 180;
        const northPole = new THREE.Vector3(
          0, // x = 0 表示在正北方
          Math.sin(latitudeRad) * radius * 1.2, // y分量决定仰角
          Math.cos(latitudeRad) * radius * 1.2 // z分量确保距离
        );
        const southPole = northPole.clone().multiplyScalar(-1);

        // 创建天极点标记
        const poleGeometry = new THREE.SphereGeometry(0.03);
        const poleMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff });

        // 北天极
        northPoleMark = new THREE.Mesh(poleGeometry, poleMaterial);
        northPoleMark.position.copy(northPole);
        scene.add(northPoleMark);

        // 南天极
        southPoleMark = new THREE.Mesh(poleGeometry, poleMaterial);
        southPoleMark.position.copy(southPole);
        scene.add(southPoleMark);

        // 天轴
        const axisGeometry = new THREE.BufferGeometry().setFromPoints([
          northPole,
          southPole,
        ]);
        const axisMaterial = new THREE.LineDashedMaterial({
          color: 0xff0000,
          dashSize: 0.1,
          gapSize: 0.05,
        });
        celestialAxis = new THREE.Line(axisGeometry, axisMaterial);
        celestialAxis.computeLineDistances(); // 计算虚线间距
        scene.add(celestialAxis);

        // 添加到需要清除的对象列表
        objectsToRemove.push(northPoleMark, southPoleMark, celestialAxis);

        // 添加天极点标签
        const northPoleLabel = document.createElement("div");
        northPoleLabel.className = "label";
        northPoleLabel.style.position = "absolute";
        northPoleLabel.style.color = "white";
        northPoleLabel.style.padding = "2px";
        northPoleLabel.style.backgroundColor = "rgba(0,0,0,0.5)";
        //northPoleLabel.textContent = "北天极";
        document.body.appendChild(northPoleLabel);

        const southPoleLabel = document.createElement("div");
        southPoleLabel.className = "label";
        southPoleLabel.style.position = "absolute";
        southPoleLabel.style.color = "white";
        southPoleLabel.style.padding = "2px";
        southPoleLabel.style.backgroundColor = "rgba(0,0,0,0.5)";
        //southPoleLabel.textContent = "南天极";
        document.body.appendChild(southPoleLabel);

        function updatePoleLabels() {
          const northVector = northPole.clone();
          northVector.project(camera);
          const northX = (northVector.x * 0.5 + 0.5) * window.innerWidth;
          const northY = (-northVector.y * 0.5 + 0.5) * window.innerHeight;
          northPoleLabel.style.left = northX + "px";
          northPoleLabel.style.top = northY + "px";

          const southVector = southPole.clone();
          southVector.project(camera);
          const southX = (southVector.x * 0.5 + 0.5) * window.innerWidth;
          const southY = (-southVector.y * 0.5 + 0.5) * window.innerHeight;
          southPoleLabel.style.left = southX + "px";
          southPoleLabel.style.top = southY + "px";
        }

        // 计算太阳轨迹
        const points = [];
        const timePoints = 100;
        const hourMarkers = [];

        // 计算日照时长和时间
        const tanDelta = Math.tan(delta);
        const tanLat = Math.tan((latitude * Math.PI) / 180);
        const product = -tanDelta * tanLat;

        let Ts, Tsunrise, Tsunset;
        let isExtreme = false;
        let extremeType = "";

        if (product > 1) {
          // 极夜
          Ts = 0;
          isExtreme = true;
          extremeType = "极夜";
        } else if (product < -1) {
          // 极昼
          Ts = 24;
          isExtreme = true;
          extremeType = "极昼";
        } else {
          // 正常情况
          Ts = (2 / 15) * Math.acos(product) * (180 / Math.PI);
        }

        const Tc = 12; // 简化为正午时间
        if (!isExtreme) {
          Tsunrise = Tc - Ts / 2;
          Tsunset = Tc + Ts / 2;
        }

        // 更新信息面板
        const infoPanel = document.getElementById("info");

        // 更新信息面板中添加法向量信息

        infoPanel.innerHTML = `
            太阳周日视运动可视化<br>
            拖动鼠标可以旋转视角<br>
            滚轮可以缩放<br>
            <hr>
            观测位置：北纬 ${latitude}°<br>
            观测日期：${year}年${month}月${date}日<br>
            赤纬角：${((delta * 180) / Math.PI).toFixed(2)}°<br>
            日照时长：${isExtreme
            ? Ts === 24
              ? "24小时0分钟"
              : "0小时0分钟"
            : `${Math.floor(Ts)}小时${Math.floor((Ts % 1) * 60)}分钟`
          }<br>
            日出时间：${isExtreme
            ? extremeType
            : `${Math.floor(Tsunrise)}:${Math.floor((Tsunrise % 1) * 60)
              .toString()
              .padStart(2, "0")}`
          }<br>
            日落时间：${isExtreme
            ? extremeType
            : `${Math.floor(Tsunset)}:${Math.floor((Tsunset % 1) * 60)
              .toString()
              .padStart(2, "0")}`
          }
        `;

        // 首先在XY平面上生成基础圆形轨迹
        for (let i = 0; i < timePoints; i++) {
          const t = (i / (timePoints - 1)) * Math.PI * 2;
          const d = radius * Math.sin(delta); // 纬圈的垂直偏移量
          const circleRadius = Math.sqrt(radius * radius - d * d); // 计算纬圈半径
          const x = circleRadius * Math.cos(t);
          const y = circleRadius * Math.sin(t);
          const z = d;

          // 计算旋转矩阵
          const zAxis = new THREE.Vector3(0, 0, 1); // 初始纬圈法向量
          const northPoleDir = new THREE.Vector3(
            0,
            Math.sin((latitude * Math.PI) / 180),
            Math.cos((latitude * Math.PI) / 180)
          ).normalize();

          // 计算旋转轴（叉积）
          const rotationAxis = new THREE.Vector3();
          rotationAxis.crossVectors(zAxis, northPoleDir).normalize();

          // 计算旋转角度（点积）
          const rotationAngle = Math.acos(zAxis.dot(northPoleDir));

          // 创建旋转矩阵
          const rotationMatrix = new THREE.Matrix4();
          rotationMatrix.makeRotationAxis(rotationAxis, rotationAngle);

          // 应用旋转
          const point = new THREE.Vector3(x, y, z);
          point.applyMatrix4(rotationMatrix);
          points.push(point);

          // 添加整点标记
          if (i % (timePoints / 24) === 0) {
            // const markerGeometry = new THREE.SphereGeometry(0.02, 8, 8);
            // const markerMaterial = new THREE.MeshBasicMaterial({ color: 0xFFA500 }); // 橙色
            // const marker = new THREE.Mesh(markerGeometry, markerMaterial);
            // marker.position.copy(point);
            // scene.add(marker);
            // hourMarkers.push(marker);
            // // 添加时间标签
            // const hour = Math.floor(i / (timePoints/24));
            // const timeLabel = document.createElement('div');
            // timeLabel.className = 'label';
            // timeLabel.style.position = 'absolute';
            // timeLabel.style.color = 'white';
            // timeLabel.style.padding = '2px';
            // timeLabel.style.backgroundColor = 'rgba(0,0,0,0.5)';
            // timeLabel.textContent = `${hour}:00`;
            // document.body.appendChild(timeLabel);
            // // 更新标签位置
            // function updateTimeLabel() {
            //     const vector = point.clone();
            //     vector.project(camera);
            //     const x2d = (vector.x * 0.5 + 0.5) * window.innerWidth;
            //     const y2d = (-vector.y * 0.5 + 0.5) * window.innerHeight;
            //     timeLabel.style.left = x2d + 'px';
            //     timeLabel.style.top = y2d + 'px';
            // }
            // orientationPoints.push({ point: marker, updateLabel: updateTimeLabel });
          }
        }

        // 创建太阳轨迹管道
        const curve = new THREE.CatmullRomCurve3(points);
        const sunPathGeometry = new THREE.TubeGeometry(
          curve,
          50,
          0.01,
          20,
          false
        );
        const sunPathMaterial = new THREE.MeshBasicMaterial({
          color: 0xffff00,
        });
        const sunPath = new THREE.Mesh(sunPathGeometry, sunPathMaterial);
        scene.add(sunPath);

        objectsToRemove.push(sunPath);

        // 动画循环
        function animate() {
          requestAnimationFrame(animate);
          controls.update();
          orientationPoints.forEach((point) => {
            if (point.updateLabel) point.updateLabel();
          });
          renderer.render(scene, camera);
        }

        // 窗口大小调整
        window.addEventListener("resize", onWindowResize, false);
        function onWindowResize() {
          camera.aspect = window.innerWidth / window.innerHeight;
          camera.updateProjectionMatrix();
          renderer.setSize(window.innerWidth, window.innerHeight);
        }

        animate();
      };
      window.onload = function () {
        updateButton.click();
      };
    }

    init();
  </script>
</head>

<body>

  <div style="position: fixed; left: 10px; top: 50%; transform: translateY(-50%)">
    <button class="button" onclick="window.location.href='十二宫图.html'">
      <img src={{ url_for('static', filename='素材/left.png' ) }} alt="moon" />
    </button>
  </div>
  <div class="center-container">
    <div id="three-container" class="image-container"></div>
  </div>
  <div id="info">
  </div>
  <div class="footer">
    <button class="calendar-btn" onclick="window.location.href='newcalendar.html'">
      <img src="{{ url_for('static', filename='素材/日历浅色.png') }}" alt="calendar" />
    </button>
    <button class="moon-btn" onclick="window.location.href='十二宫图.html'">
      <img src="{{ url_for('static', filename='素材/可视化深色.png') }}" alt="moon" />
    </button>
    <button class="data-btn" onclick="window.location.href='newdata.html'">
      <img src="{{ url_for('static', filename='素材/知识浅色.png') }}" alt="data" />
    </button>
    <button class="index-btn" onclick="window.location.href='newai.html'">
      <img src="{{ url_for('static', filename='素材/大模型.png') }}" alt="index" />
    </button>
  </div>
</body>

</html>